Passed
Push — master ( 7eebaa...3300c1 )
by EMP
06:45
created

main.js ➔ showFiles   F

Complexity

Conditions 32

Size

Total Lines 134
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
eloc 91
dl 0
loc 134
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like main.js ➔ showFiles often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"use strict";
2
3
sodium.ready.then(function() {
4
5
let isReady = true;
6
7
let vaultPage = -4;
8
const vault = new PostVault(function(ok) {
0 ignored issues
show
Bug introduced by
The variable PostVault seems to be never declared. If this is a global, consider adding a /** global: PostVault */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Unused Code introduced by
The parameter ok is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
9
	vaultPage = -3;
10
});
11
12
const ae = new AllEars(function(ok) {
13
	if (!ok) {
14
		document.getElementById("greeting").textContent = "Failed loading All-Ears";
15
		return;
16
	}
17
18
	try {
19
		if (localStorage.greeting) {
20
			document.getElementById("greeting").textContent = localStorage.greeting;
21
			document.getElementById("txt_pg").value = localStorage.greeting;
22
		} else localStorage.greeting = document.getElementById("greeting").textContent;
23
	} catch(e) {
24
		document.getElementById("btn_pg").disabled = true;
25
		document.getElementById("txt_pg").disabled = true;
26
		document.getElementById("txt_pg").className = "ita";
27
		document.getElementById("txt_pg").value = "LocalStorage inaccessible";
28
	}
29
30
	document.getElementById("txt_umk").maxLength = "60";
31
});
32
33
function TabState(cur, max, btnDele, btnUpdt) {
34
	this.cur = cur;
35
	this.max = max;
36
	this.btnDele = btnDele;
37
	this.btnUpdt = btnUpdt;
38
}
39
40
const tabs = [
41
	new TabState(0, 0, false, true), // Inbox
42
	new TabState(0, 0, false, false), // Outbx
43
	new TabState(0, 1, true,  false), // Write
44
	new TabState(0, 2, false, false), // Notes
45
	new TabState(0, 2, false, false) // Tools
46
];
47
48
function MsgInfo(msgId, msgType, msgNum) {
49
	this.id = msgId;
50
	this.type = msgType;
51
	this.num = msgNum;
52
}
53
54
let msgDisplay = new MsgInfo(null, null, null);
55
let showHeaders = false;
56
let rowsPerPage = 0;
57
58
let tab = 0;
59
const TAB_INBOX = 0;
60
const TAB_DRBOX = 1;
61
const TAB_WRITE = 2;
62
const TAB_NOTES = 3;
63
const TAB_TOOLS = 4;
64
65
function errorDialog(err, focusAfter) {
66
	if (typeof(err) !== "number" || err < 1) return;
67
68
	let btnDisable = [];
69
	const buttons = document.querySelectorAll("nav > button");
70
	buttons.forEach(function(btn) {
71
		btnDisable.push(btn.disabled);
72
		btn.disabled = true;
73
	});
74
75
	const errMsg = ae.getErrorMessage(err);
76
77
	const dlg = document.querySelector("dialog");
78
	dlg.children[0].style.height = getComputedStyle(document.querySelector("#main1 > div[class='mid']")).height;
79
	dlg.querySelector("h1").textContent = "ERROR " + ((err >= 400) ? err : ("0x" + err.toString(16).padStart(2, "0").toUpperCase()));
80
	dlg.querySelector("p").textContent = (typeof(errMsg) === "string") ? errMsg : errMsg[1];
81
	dlg.show();
82
83
	document.querySelector("dialog > div").onclick = function() {
84
		buttons.forEach(function(btn, i) {btn.disabled = btnDisable[i];});
85
		dlg.close();
86
		if (focusAfter) focusAfter.focus();
87
	};
88
89
	document.onkeyup = function(event) {
90
		document.onkeyup = null;
91
		event.preventDefault();
92
93
		buttons.forEach(function(btn, i) {btn.disabled = btnDisable[i];});
94
		dlg.close();
95
		if (focusAfter) focusAfter.focus();
96
	};
97
}
98
99
function getCountryFlag(countryCode) {
100
	return (!countryCode || countryCode.length !== 2 || countryCode === "??") ? "❔" : sodium.to_string(new Uint8Array([
101
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
102
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
103
	]));
104
}
105
106
function getClockIcon(d) {
107
	const h24 = d.getUTCHours();
108
	let h12 = (h24 === 0 ? 12 : ((h24 > 12) ? h24 - 12 : h24));
109
110
	const m60 = (d.getUTCMinutes() * 60) + d.getUTCSeconds();
111
	let m30 = 0;
112
	if (m60 <= 900) { // <= 15: round down to this hour
113
		m30 = 0;
114
	} else if (m60 > 900 && m60 < 2700) { // 15..45: round to half-past this hour
115
		m30 = 12;
116
	} else { // >= 45: round up to next hour
117
		h12++;
118
		m30 = 0;
119
	}
120
121
	return String.fromCodePoint((128335 + h12) + m30);
122
}
123
124
function clearDisplay() {
125
	document.getElementById("btn_mnext").disabled = true;
126
	document.getElementById("btn_mprev").disabled = true;
127
	document.getElementById("readmsg_export").hidden = true;
128
129
	const el = document.querySelector("#readmsg_main > img, #readmsg_main > audio, #readmsg_main > video, #readmsg_main > embed, #readmsg_main > iframe");
130
	if (!el) return;
131
	if (el.src) URL.revokeObjectURL(el.src);
132
	el.remove();
133
}
134
135
function clearMsgFlags() {
136
	document.getElementById("readmsg_flags").children[0].replaceChildren();
137
}
138
139
function addMsgFlag(abbr, abbrTitle) {
140
	const parent = document.getElementById("readmsg_flags").children[0];
141
142
	const el = document.createElement("abbr");
143
	el.title = abbrTitle;
144
	el.textContent = abbr;
145
146
	parent.appendChild(document.createTextNode(" "));
147
	parent.appendChild(el);
148
}
149
150
function displayFile(isHistory, num, showNext) {
151
	if (num < 0 || num >= ae.getUplMsgCount()) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
152
153
	const fileType = ae.getUplMsgType(num);
154
	if (!fileType) {
155
		if (isHistory) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
156
		if (showNext === true) return displayFile(false, num + 1, true);
157
		if (showNext === false) return displayFile(false, num - 1, false);
158
		ae.downloadUplMsg(num); return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
159
	}
160
161
	clearDisplay();
162
	document.querySelector("article").scroll(0, 0);
163
	document.querySelector("article").setAttribute("data-msgid", ae.getUplMsgId(num));
164
165
	document.getElementById("btn_mdele").disabled = false;
166
	document.getElementById("btn_msave").disabled = false;
167
	document.getElementById("btn_reply").disabled = true;
168
169
	document.getElementById("btn_msave").onclick = function() {ae.downloadUplMsg(num);};
170
171
	document.getElementById("readmsg_info").hidden = true;
172
	document.querySelector("#readmsg_main > h1").textContent = ae.getUplMsgTitle(num);
173
174
	msgDisplay = new MsgInfo(ae.getUplMsgId(num), "upl", num);
175
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
176
177
	document.getElementById("main2").hidden = false;
178
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
179
180
	document.getElementById("btn_mnext").disabled = (num === ae.getUplMsgCount() - 1);
181
	document.getElementById("btn_mprev").disabled = (num === 0);
182
	document.getElementById("btn_mnext").onclick = function() {displayFile(false, num + 1, true);};
183
	document.getElementById("btn_mprev").onclick = function() {displayFile(false, num - 1, false);};
184
185
	if (fileType === "text") {
186
		document.querySelector("#readmsg_main > pre").hidden = false;
187
		try {
188
			document.querySelector("#readmsg_main > pre").textContent = sodium.to_string(ae.getUplMsgBody(num));
189
		} catch(e) {
190
			document.querySelector("#readmsg_main > pre").textContent = "Failed decoding body: " + e.message;
191
		}
192
		return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
193
	}
194
195
	document.querySelector("#readmsg_main > pre").hidden = true;
196
	let el;
197
198
	switch (fileType) {
199
		case "image": {
200
			el = document.createElement("img");
201
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer]));
202
			el.onclick = function() {
203
				if (!document.fullscreen)
204
					this.requestFullscreen();
205
				else
206
					document.exitFullscreen();
207
			};
208
		break;}
209
210
		case "audio":
211
		case "video": {
212
			el = document.createElement(fileType);
213
			el.controls = "controls";
214
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer]));
215
		break;}
216
217
		case "pdf": {
218
			el = document.createElement("embed");
219
			el.type = "application/pdf";
220
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer], {type: "application/pdf"}));
221
		break;}
222
223
		case "html": {
224
			el = document.createElement("iframe");
225
			el.allow = "vertical-scroll";
226
			el.sandbox = "";
227
			el.referrerPolicy = "no-referrer";
228
229
			try {
230
				const sanBody = document.createElement("body");
231
				sanBody.setHTML(sodium.to_string(ae.getUplMsgBody(num).buffer), {sanitizer: new Sanitizer({
0 ignored issues
show
Bug introduced by
The variable Sanitizer seems to be never declared. If this is a global, consider adding a /** global: Sanitizer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
232
					"allowElements": [
233
						"a","div","p",
234
						"h1","h2","h3","h4","h5","h6",
235
						"em","strong","b","i","u"
236
					],
237
					"allowAttributes": {
238
						"href": ["*"]
239
					}
240
				})});
241
242
				el.srcdoc =
243
				"<!doctype html><html>" +
244
					"<head>" +
245
						"<style>" +
246
							"html, body {background: #080a08; color: #fff; scrollbar-color: #222 #333;}\n" +
247
							"body {opacity:0.55;}\n" +
248
							"body > *:first-child {margin-top: 0; padding-top: 0;}\n" +
249
							"a {color: #fff;}\n" +
250
							"button, input, select, textarea {background: #000; color: #fff;}\n" +
251
						"</style>" +
252
					"</head>" +
253
					sanBody.outerHTML +
254
				"</html>";
255
			} catch(e) {
256
				el.srcdoc = "<!doctype html><html><head><style>body {background: #080a08; color: #fff; opacity:0.55;} h1 {margin: 0;}</style><body><h1>Error</h1><p>" + e.message + "</p></body></html>";
257
			}
258
		break;}
259
260
		case "svg": {
261
			el = document.createElement("iframe");
262
			el.allow = "";
263
			el.sandbox = "";
264
			el.referrerPolicy = "no-referrer";
265
			el.srcdoc = "<!doctype><html><head><style>body,html,svg {margin: 0; padding: 0; border: 0; height: 100%; width: 100%; display: block; background: #080a08;}</style></head><body>" + sodium.to_string(ae.getUplMsgBody(num).buffer) + "</body></html>";
266
		break;}
267
268
		default: return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
269
	}
270
271
	document.getElementById("readmsg_main").appendChild(el);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
272
}
273
274
function displayMsg(isHistory, isInt, num) {
275
	clearDisplay();
276
	document.getElementById("btn_mdele").disabled = false;
277
278
	document.querySelector("article").scroll(0, 0);
279
	document.querySelector("article").setAttribute("data-msgid", isInt? ae.getIntMsgId(num) : ae.getExtMsgId(num));
280
281
	document.getElementById("btn_msave").disabled = false;
282
	document.getElementById("btn_msave").onclick = function() {displayExport(false, isInt, num);};
283
284
	const ts = isInt? ae.getIntMsgTime(num) : ae.getExtMsgTime(num);
285
286
	if (!isInt || (ae.getIntMsgFrom(num) !== "public" && ae.getIntMsgFrom(num) !== "system")) {
287
		document.getElementById("btn_reply").disabled = false;
288
289
		document.getElementById("btn_reply").onclick = function() {
290
			document.getElementById("write_recv").value = isInt? ae.getIntMsgFrom(num) : ae.getExtMsgReplyAddress(num);
291
			document.getElementById("write_subj").value = isInt? ae.getIntMsgTitle(num) : ae.getExtMsgTitle(num);
292
			if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
293
			document.querySelector("#write2_pkey > input").value = isInt? ae.getIntMsgApk(num) : "";
294
295
			document.getElementById("write_recv").readOnly = !isInt;
296
			document.getElementById("write_subj").readOnly = !isInt;
297
			document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : ae.getExtMsgHdrId(num));
298
299
			tabs[TAB_WRITE].cur = 0;
300
			document.getElementById("btn_write").disabled = false;
301
			document.getElementById("btn_write").click();
302
			document.getElementById("write_body").focus();
303
304
			for (const opt of document.getElementById("write_from").options) {
305
				if (opt.value === (isInt ? ae.getIntMsgTo(num) : ae.getExtMsgEnvTo(num).split("@")[0].toLowerCase())) {
306
					opt.selected = true;
307
				}
308
			}
309
		};
310
	} else {
311
		document.getElementById("btn_reply").disabled = true;
312
	}
313
314
	document.getElementById("readmsg_info").hidden = false;
315
	document.querySelector("#readmsg_main > pre").hidden = false;
316
317
	document.getElementById("readmsg_envto").textContent = isInt ? "" : ae.getExtMsgEnvTo(num);
318
	document.getElementById("readmsg_hdrto").textContent = isInt ? ae.getIntMsgTo(num) : (ae.getExtMsgHdrTo(num));
319
	if(!isInt && ae.getExtMsgDnTo(num)) {
320
		const span = document.createElement("span");
321
		span.className = "sans";
322
		span.textContent = " • " + ae.getExtMsgDnTo(num);
323
		document.getElementById("readmsg_hdrto").appendChild(span);
324
	}
325
326
	const tzOs = new Date().getTimezoneOffset();
327
	const msgDate = new Date((ts * 1000) + (tzOs * -60000));
328
	document.getElementById("readmsg_date").children[0].textContent = getClockIcon(msgDate);
329
	document.getElementById("readmsg_date").children[1].dateTime = new Date(ts * 1000).toISOString();
330
331
	if (isInt) {
332
		document.querySelector("#readmsg_main > h1").textContent = ae.getIntMsgTitle(num);
333
		document.querySelector("#readmsg_main > pre").textContent = ae.getIntMsgBody(num);
334
335
		document.getElementById("readmsg_date").children[1].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ");
336
337
		document.getElementById("readmsg_ip").style.visibility = "hidden";
338
		document.getElementById("readmsg_rdns").style.visibility = "hidden";
339
		document.getElementById("readmsg_dkim").style.visibility = "hidden";
340
		document.getElementById("readmsg_greet").style.visibility = "hidden";
341
		document.getElementById("readmsg_cert").style.visibility = "hidden";
342
		document.getElementById("readmsg_envfrom").style.visibility = "hidden";
343
		document.getElementById("readmsg_envto").style.visibility = "hidden";
344
345
		if (ae.getIntMsgFrom(num) !== "system" && ae.getIntMsgFrom(num) !== "public") {
346
			document.getElementById("readmsg_tls").style.visibility = "visible";
347
			document.getElementById("readmsg_tls").children[0].textContent = ae.getIntMsgApk(num);
348
		} else document.getElementById("readmsg_tls").style.visibility = "hidden";
349
350
		let symbol = document.createElement("span");
351
		if      (ae.getIntMsgLevel(num) === 3 && ae.getIntMsgFrom(num) === "system") {symbol.title = "System message"; symbol.textContent = "🅢";}
352
		else if (ae.getIntMsgLevel(num) === 3 && ae.getIntMsgFrom(num) === "public") {symbol.title = "Public announcement"; symbol.textContent = "🅟";}
353
		else if (ae.getIntMsgLevel(num) === 3) {symbol.title = "Administrator"; symbol.textContent = "🅐";}
354
		else if (ae.getIntMsgLevel(num) === 2) {symbol.title = "Level 2";  symbol.textContent = "➋";}
355
		else if (ae.getIntMsgLevel(num) === 1) {symbol.title = "Level 1";  symbol.textContent = "➊";}
356
		else if (ae.getIntMsgLevel(num) === 0) {symbol.title = "Level 0";  symbol.textContent = "🄌";}
357
		else {symbol.title = "Invalid level"; symbol.textContent = "⚠";}
358
359
		document.getElementById("readmsg_hdrfrom").replaceChildren(symbol, document.createTextNode(" " + ae.getIntMsgFrom(num)));
360
361
		clearMsgFlags();
362
		if ( ae.getIntMsgFlagE2ee(num)) addMsgFlag("E2EE", "End-to-end encrypted");
363
	} else {
364
		const headers = document.createElement("p");
365
		headers.textContent = ae.getExtMsgHeaders(num);
366
		headers.className = "mono";
367
		headers.hidden = !showHeaders;
368
369
		const body = document.createElement("p");
370
		body.innerHTML = ae.getExtMsgBody(num, false);
371
372
		document.querySelector("#readmsg_main > pre").replaceChildren(headers, body);
373
374
		const h1 = document.querySelector("#readmsg_main > h1");
375
		h1.textContent = ae.getExtMsgTitle(num);
376
		h1.style.cursor = headers.textContent? "pointer" : "";
377
		h1.onclick = function() {
378
			if (!headers.textContent) return;
379
			showHeaders = !showHeaders;
380
			headers.hidden = !showHeaders;
381
		};
382
383
		let hdrSecs = Math.abs(ae.getExtMsgHdrTime(num));
384
		let hdrTime = "";
385
		if (hdrSecs >= 3600) {
386
			const hdrHours = Math.floor(hdrSecs / 3600);
387
			hdrTime += hdrHours.toString() + "h ";
388
			hdrSecs -= hdrHours * 3600;
389
		}
390
		if (hdrSecs >= 60) {
391
			const hdrMins = Math.floor(hdrSecs / 60);
392
			hdrTime += hdrMins.toString() + "m ";
393
			hdrSecs -= hdrMins * 60;
394
		}
395
		hdrTime += hdrSecs + "s";
396
397
		const hdrTz = (ae.getExtMsgHdrTz(num) >= 0 ? "+" : "-") + Math.floor(Math.abs(ae.getExtMsgHdrTz(num)) / 60).toString().padStart(2, "0") + (Math.abs(ae.getExtMsgHdrTz(num)) % 60).toString().padStart(2, "0");
398
399
		let spans = [document.createElement("span"), document.createElement("span"), document.createElement("span")];
400
		spans[0].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ");
401
		spans[1].className = "sans";
402
		spans[1].textContent = " • ";
403
		spans[2].textContent = hdrTz + " " + ((ae.getExtMsgHdrTime(num) >= 0) ? "+" : "-") + hdrTime;
404
		document.getElementById("readmsg_date").children[1].replaceChildren(...spans);
405
406
		document.getElementById("readmsg_ip").style.visibility = "visible";
407
		document.getElementById("readmsg_rdns").style.visibility = "visible";
408
		document.getElementById("readmsg_dkim").style.visibility = "visible";
409
		document.getElementById("readmsg_greet").style.visibility = "visible";
410
		document.getElementById("readmsg_tls").style.visibility = "visible";
411
		document.getElementById("readmsg_cert").style.visibility = "visible";
412
		document.getElementById("readmsg_envfrom").style.visibility = "visible";
413
		document.getElementById("readmsg_envto").style.visibility = "visible";
414
415
		// DKIM
416
		let dkim = "";
417
		if (ae.getExtMsgDkim(num)) {
418
			[ // Look for a matching domain in this order
419
				ae.getExtMsgHdrFrom(num).split("@")[1],
420
				ae.getExtMsgEnvFrom(num).split("@")[1],
421
				ae.getExtMsgRdns(num),
422
				ae.getExtMsgGreet(num),
423
				ae.getExtMsgTlsDomain(num)
424
			].forEach(function(dom) {
425
				if (dkim) return;
426
				for (let i = 0; i < ae.getExtMsgDkim(num).domain.length; i++) {
427
					if (ae.getExtMsgDkim(num).domain[i] === dom) {
428
						dkim = dom + " ✓";
429
						return;
430
					}
431
				}
432
			});
433
434
			if (!dkim) dkim = ae.getExtMsgDkim(num).domain[0]; // Default to first signature domain
435
		}
436
437
		if (ae.getExtMsgFlagDkFl(num)) dkim += " (fail)";
438
439
		// Left side
440
		document.getElementById("readmsg_country").textContent = getCountryFlag(ae.getExtMsgCcode(num));
441
		document.getElementById("readmsg_country").title = ae.getExtMsgCname(num);
442
		document.getElementById("readmsg_ip").children[1].textContent = ae.getExtMsgIp(num) + (ae.getExtMsgFlagIpBl(num) ? " ❗" : "");
443
		document.getElementById("readmsg_ip").children[2].textContent = " • " + ae.getExtMsgAuSys(num);
444
		document.getElementById("readmsg_tls").children[0].textContent = ae.getExtMsgTLS(num);
445
446
		// Right side
447
		document.getElementById("readmsg_greet").children[0].textContent = ae.getExtMsgGreet(num) + (ae.getExtMsgFlagGrDm(num) ? " ✓" : "");
448
		document.getElementById("readmsg_rdns").children[0].textContent = ae.getExtMsgRdns(num) + (ae.getExtMsgGreet(num).toLowerCase() === ae.getExtMsgRdns(num).toLowerCase() ? " ✓" : "");
449
		document.getElementById("readmsg_cert").children[0].textContent = ae.getExtMsgTlsDomain(num) ? (ae.getExtMsgTlsDomain(num) + " ✓") : "";
450
		document.getElementById("readmsg_dkim").children[0].textContent = dkim;
451
		document.getElementById("readmsg_envfrom").textContent = ae.getExtMsgEnvFrom(num);
452
		document.getElementById("readmsg_hdrfrom").textContent = ae.getExtMsgHdrFrom(num);
453
		if (ae.getExtMsgDnFrom(num)) {
454
			const span = document.createElement("span");
455
			span.className = "sans";
456
			span.textContent = " • " + ae.getExtMsgDnFrom(num);
457
			document.getElementById("readmsg_hdrfrom").appendChild(span);
458
		}
459
460
		clearMsgFlags();
461
		if (!ae.getExtMsgFlagPExt(num)) addMsgFlag("SMTP", "The sender did not use the Extended (ESMTP) protocol");
462
		if ( ae.getExtMsgFlagRare(num)) addMsgFlag("RARE", "The sender issued unusual command(s)");
463
		if ( ae.getExtMsgFlagFail(num)) addMsgFlag("FAIL", "The sender issued invalid command(s)");
464
		if ( ae.getExtMsgFlagPErr(num)) addMsgFlag("PROT", "The sender violated the protocol");
465
	}
466
467
	document.getElementById("readmsg_main").hidden = false;
468
	document.getElementById("main2").hidden = false;
469
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
470
471
	msgDisplay = new MsgInfo(isInt? ae.getIntMsgId(num) : ae.getExtMsgId(num), isInt? "int" : "ext", num);
472
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
473
}
474
475
function displayExport(isHistory, isInt, num) {
476
	clearDisplay();
477
	document.getElementById("readmsg_main").hidden = true;
478
	document.getElementById("readmsg_export").hidden = false;
479
	document.getElementById("btn_msave").blur();
480
	document.getElementById("btn_msave").disabled = true;
481
	document.getElementById("btn_reply").disabled = true;
482
	document.getElementById("btn_mdele").disabled = true;
483
484
//	document.querySelector("#readmsg_export > div:nth-child(1)").onclick = function() {};
485
	document.querySelector("#readmsg_export > div:nth-child(2)").onclick = function() {if (isInt) {ae.downloadIntMsg(num);} else {ae.downloadExtMsg(num);} displayMsg(false, isInt, num);};
486
	document.querySelector("#readmsg_export > div:nth-child(3)").onclick = function() {if (isInt) {ae.htmlIntMsg(num, true);} else {ae.htmlExtMsg(num, true);} displayMsg(false, isInt, num);};
487
	document.querySelector("#readmsg_export > div:nth-child(4)").onclick = function() {if (isInt) {ae.txtIntMsg(num, true);} else {ae.txtExtMsg(num, true);} displayMsg(false, isInt, num);};
488
	document.querySelector("#readmsg_export > div:nth-child(5)").onclick = function() {if (isInt) {ae.printIntMsg(num);} else {ae.printExtMsg(num);} displayMsg(false, isInt, num);};
489
	document.querySelector("#readmsg_export > div:nth-child(6)").onclick = function() {navigator.clipboard.writeText(isInt? ae.txtIntMsg(num, false) : ae.txtExtMsg(num, false)); displayMsg(false, isInt, num);};
490
491
	msgDisplay = new MsgInfo(isInt? ae.getIntMsgId(num) : ae.getExtMsgId(num), isInt? "int_exp" : "ext_exp", num);
492
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
493
}
494
495
function displayOutMsg(isHistory, num) {
496
	clearDisplay();
497
	document.querySelector("article").scroll(0, 0);
498
	document.querySelector("article").setAttribute("data-msgid", ae.getOutMsgId(num));
499
500
	document.getElementById("btn_mdele").disabled = false;
501
	document.getElementById("btn_msave").disabled = true;
502
	document.getElementById("btn_reply").disabled = true;
503
504
	document.getElementById("readmsg_info").hidden = false;
505
	document.querySelector("#readmsg_main > pre").hidden = false;
506
507
	document.querySelector("#readmsg_main > h1").textContent = ae.getOutMsgSubj(num);
508
	document.querySelector("#readmsg_main > pre").textContent = ae.getOutMsgBody(num);
509
510
	document.getElementById("readmsg_dkim").style.visibility    = "hidden";
511
	document.getElementById("readmsg_hdrto").style.visibility   = "visible";
512
	document.getElementById("readmsg_hdrfrom").style.visibility = "visible";
513
	document.getElementById("readmsg_envto").style.visibility   = "visible";
514
	document.getElementById("readmsg_envfrom").style.visibility = "hidden";
515
516
	document.getElementById("readmsg_hdrfrom").textContent = ae.getOutMsgFrom(num);
517
518
	document.getElementById("readmsg_envto").textContent = ae.getOutMsgMxDom(num);
519
	document.getElementById("readmsg_hdrto").textContent = ae.getOutMsgTo(num);
520
521
	const ts = ae.getOutMsgTime(num);
522
	const tzOs = new Date().getTimezoneOffset();
523
	document.getElementById("readmsg_date").children[1].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ");
524
525
	const isInt = ae.getOutMsgIsInt(num);
526
	document.getElementById("readmsg_ip").style.visibility    = isInt? "hidden" : "visible";
527
	document.getElementById("readmsg_rdns").style.visibility  = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
528
	document.getElementById("readmsg_tls").style.visibility   = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
529
	document.getElementById("readmsg_cert").style.visibility  = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
530
	document.getElementById("readmsg_greet").style.visibility = isInt? "hidden" : "visible";
531
532
	if (!isInt) {
533
		document.getElementById("readmsg_ip").children[1].textContent = ae.getOutMsgIp(num);
534
		document.getElementById("readmsg_country").textContent = getCountryFlag(ae.getOutMsgCcode(num));
535
		document.getElementById("readmsg_country").title = ae.getOutMsgCname(num);
536
//		document.getElementById("readmsg_tls").children[0].textContent = ae.getOutMsgTLS(num);
537
		document.getElementById("readmsg_greet").children[0].textContent = ae.getOutMsgGreet(num);
538
	}
539
540
	clearMsgFlags();
541
	if ( ae.getOutMsgFlagE2ee(num)) addMsgFlag("E2EE", "End-to-end encrypted");
542
543
	document.getElementById("main2").hidden = false;
544
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
545
546
	msgDisplay = new MsgInfo(ae.getOutMsgId(num), "out", num);
547
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
548
}
549
550
function updateAddressButtons() {
551
	const limitReached = (ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31);
552
	document.getElementById("btn_address_create_normal").disabled = (limitReached || ae.getAddressCountNormal() >= ae.getLimitNormalA(ae.getOwnLevel()));
553
	document.getElementById("btn_address_create_shield").disabled = (limitReached || ae.getAddressCountShield() >= ae.getLimitShieldA(ae.getOwnLevel()));
554
}
555
556
function updateAddressCounts() {
557
	document.querySelector("#tbd_accs > tr > td:nth-child(3)").textContent = ae.getAddressCountNormal();
558
	document.querySelector("#tbd_accs > tr > td:nth-child(4)").textContent = ae.getAddressCountShield();
559
560
	document.getElementById("limit_normal").textContent = (ae.getAddressCountNormal() + "/" + ae.getLimitNormalA(ae.getOwnLevel())).padStart(ae.getLimitNormalA(ae.getOwnLevel()) > 9 ? 5 : 1);
561
	document.getElementById("limit_shield").textContent = (ae.getAddressCountShield() + "/" + ae.getLimitShieldA(ae.getOwnLevel())).padStart(ae.getLimitShieldA(ae.getOwnLevel()) > 9 ? 5 : 1);
562
	document.getElementById("limit_total").textContent = ((ae.getAddressCountNormal() + ae.getAddressCountShield()) + "/" + ae.getAddrPerUser()).padStart(5);
563
564
	updateAddressButtons();
565
//	document.getElementById("getapk_result").textContent = ae.getOwnApk(document.getElementById("getapk_addr").value);
566
}
567
568
function addOwnAccount() {
569
	const row = document.getElementById("tbd_accs").insertRow(-1);
570
571
	let cell;
572
	cell = row.insertCell(-1); cell.textContent = ae.uidToName(ae.getOwnUid());
573
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.getTotalMsgBytes() / 1048576); // MiB
574
	cell = row.insertCell(-1); cell.textContent = ae.getAddressCountNormal();
575
	cell = row.insertCell(-1); cell.textContent = ae.getAddressCountShield();
576
577
	cell = row.insertCell(-1);
578
	let btn = document.createElement("button");
579
	btn.type = "button";
580
	btn.textContent = "+";
581
	btn.disabled = true;
582
	cell.appendChild(btn);
583
584
	cell = row.insertCell(-1); cell.textContent = ae.getOwnLevel();
585
586
	cell = row.insertCell(-1);
587
	btn = document.createElement("button");
588
	btn.type = "button";
589
	btn.textContent = "−";
590
	btn.disabled = true;
591
	btn.id = "btn_lowme";
592
	btn.onclick = function() {
593
		const newLevel = parseInt(row.cells[5].textContent, 10) - 1;
594
		ae.Account_Update(ae.getOwnUid(), newLevel, function(error) {
595
			if (error === 0) {
596
				row.cells[5].textContent = newLevel;
597
				if (newLevel === 0) {document.getElementById("btn_lowme").disabled = true;}
598
			} else errorDialog(error);
599
		});
600
	};
601
	cell.appendChild(btn);
602
603
	cell = row.insertCell(-1);
604
	btn = document.createElement("button");
605
	btn.type = "button";
606
	btn.textContent = "X";
607
	btn.disabled = true;
608
	btn.id = "btn_delme";
609
	btn.onclick = function() {
610
		ae.Account_Delete(ae.getOwnUid(), function(error) {
611
			if (error === 0) {
612
				row.remove();
613
				document.getElementById("fs_users").disabled = true;
614
			} else errorDialog(error);
615
		});
616
	};
617
	cell.appendChild(btn);
618
}
619
620
function adjustLevel(uid, level, c) {
621
	const fs = document.getElementById("tbl_accs");
622
	fs.disabled = true;
623
624
	ae.Account_Update(uid, level, function(error) {
625
		fs.disabled = false;
626
627
		if (error === 0) {
628
			c[4].children[0].disabled = (level === 3);
629
			c[5].textContent = level;
630
			c[6].children[0].disabled = (level === 0);
631
		} else errorDialog(error);
632
	});
633
}
634
635
function addMsg(isInt, i) {
636
	const row = document.getElementById("tbl_inbox").insertRow(-1);
637
	row.setAttribute("data-msgid", isInt? ae.getIntMsgId(i) : ae.getExtMsgId(i));
638
639
	const ts = isInt? ae.getIntMsgTime(i) : ae.getExtMsgTime(i);
640
	const el = document.createElement("time");
641
	el.dateTime = new Date(ts * 1000).toISOString();
642
	el.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
643
	let cell = row.insertCell(-1);
644
	cell.appendChild(el);
645
646
	cell = row.insertCell(-1);
647
	cell.textContent = isInt? ae.getIntMsgTitle(i) : ae.getExtMsgTitle(i);
648
	if (!cell.textContent) cell.textContent = "(fail)";
649
650
	if (isInt) {
651
		cell = row.insertCell(-1);
652
		cell.textContent = ae.getIntMsgFrom(i);
653
		cell.className = (ae.getIntMsgFrom(i).length === 16) ? "mono" : "";
654
	} else {
655
		let from1 = ae.getExtMsgHdrFrom(i);
656
		if (!from1) from1 = ae.getExtMsgEnvFrom(i);
657
		const from2 = from1.substring(from1.indexOf("@") + 1);
658
		cell = row.insertCell(-1);
659
		cell.textContent = from1.substring(0, from1.indexOf("@"));
660
661
		const flag = document.createElement("abbr");
662
		flag.textContent = getCountryFlag(ae.getExtMsgCcode(i));
663
		flag.title = ae.getExtMsgCname(i);
664
665
		const fromText = document.createElement("span");
666
		fromText.textContent = " " + from2;
667
668
		cell = row.insertCell(-1);
669
		cell.appendChild(flag);
670
		cell.appendChild(fromText);
671
	}
672
673
	row.onclick = function() {
674
		displayMsg(false, isInt, i);
675
	};
676
}
677
678
function setRowsPerPage(tbl) {
679
	tbl.replaceChildren();
680
	const row = tbl.insertRow(-1);
681
	const cell = row.insertCell(-1);
682
	cell.textContent = "0";
683
	rowsPerPage = Math.floor(getComputedStyle(tbl).height.replace("px", "") / getComputedStyle(tbl.getElementsByTagName("tr")[0]).height.replace("px", ""));
684
	tbl.replaceChildren();
685
}
686
687
function showInbox() {
688
	const tbl = document.getElementById("tbl_inbox");
689
	if (!document.getElementById("main1").hidden) setRowsPerPage(tbl);
690
691
	const maxExt = ae.getExtMsgCount();
692
	const maxInt = ae.getIntMsgCount();
693
	const loadMore = ae.getReadyMsgBytes() < ae.getTotalMsgBytes();
694
695
	if (maxExt + maxInt > 0) {
696
		tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - (loadMore? 0 : 1)) / rowsPerPage);
697
		document.getElementById("btn_rght").disabled = (tabs[TAB_INBOX].cur >= tabs[TAB_INBOX].max);
698
		tbl.replaceChildren();
699
700
		let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
701
		let numExt = 0;
702
		let numInt = 0;
703
		let numAdd = 0;
704
705
		while (numAdd < rowsPerPage) {
706
			const tsInt = (numInt < maxInt) ? ae.getIntMsgTime(numInt) : -1;
707
			const tsExt = (numExt < maxExt) ? ae.getExtMsgTime(numExt) : -1;
708
			if (tsInt === -1 && tsExt === -1) break;
709
710
			if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
711
				if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
712
				numInt++;
713
			} else if (tsExt !== -1) {
714
				if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
715
				numExt++;
716
			}
717
		}
718
	} else {
719
		tabs[TAB_INBOX].max = 0;
720
	}
721
722
	if (loadMore && tabs[TAB_INBOX].cur >= tabs[TAB_INBOX].max) {
723
		const row = tbl.insertRow(-1);
724
		const cell = row.insertCell(-1);
725
		cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
726
727
		row.onclick = function() {
728
			tbl.style.opacity = 0.5;
729
730
			ae.Message_Browse(false, false, function(errorBrowse) {
731
				tbl.style.opacity = 1;
732
733
				if (errorBrowse !== 0) {
734
					errorDialog(errorBrowse);
735
					return;
736
				}
737
738
				showInbox();
739
			});
740
		};
741
	}
742
}
743
744
function showDrbox() {
745
	const tbl = document.getElementById("tbl_drbox");
746
	if (!document.getElementById("main1").hidden) setRowsPerPage(tbl);
747
748
	const drCount = ae.getOutMsgCount();
749
	const loadMore = ae.getReadyMsgBytes() < ae.getTotalMsgBytes();
750
751
	if (drCount > 0) {
752
		tabs[TAB_DRBOX].max = Math.floor((drCount - (loadMore? 0 : 1)) / rowsPerPage);
753
		document.getElementById("btn_rght").disabled = (tabs[TAB_DRBOX].cur >= tabs[TAB_DRBOX].max);
754
		tbl.replaceChildren();
755
756
		let skipMsgs = rowsPerPage * tabs[TAB_DRBOX].cur;
757
		let numAdd = 0;
758
759
		for (let i = 0; numAdd < rowsPerPage && i < drCount; i++) {
760
			if (skipMsgs > 0) {
761
				skipMsgs--;
762
				continue;
763
			}
764
765
			const row = tbl.insertRow(-1);
766
			row.setAttribute("data-msgid", ae.getOutMsgId(i));
767
768
			let cell;
769
			cell = row.insertCell(-1); cell.textContent = new Date(ae.getOutMsgTime(i) * 1000).toISOString().slice(0, 10);
770
			cell = row.insertCell(-1); cell.textContent = ae.getOutMsgSubj(i);
771
			row.onclick = function() {displayOutMsg(false, i);};
772
773
			numAdd++;
774
		}
775
	} else {
776
		tabs[TAB_DRBOX].max = 0;
777
	}
778
779
	if (loadMore && tabs[TAB_DRBOX].cur >= tabs[TAB_DRBOX].max) {
780
		const row = tbl.insertRow(-1);
781
		const cell = row.insertCell(-1);
782
		cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
783
784
		row.onclick = function() {
785
			tbl.style.opacity = 0.5;
786
787
			ae.Message_Browse(false, false, function(errorBrowse) {
788
				tbl.style.opacity = 1;
789
790
				if (errorBrowse !== 0) {
791
					errorDialog(errorBrowse);
792
					return;
793
				}
794
795
				showDrbox();
796
			});
797
		};
798
	}
799
}
800
801
function showFiles() {
802
	const tbl = document.getElementById("tbl_files");
803
	if (!document.getElementById("main1").hidden) setRowsPerPage(tbl);
804
805
	const msgCount = ae.getUplMsgCount() + ((vaultPage >= 0) ? vault.getTotalFiles() : 0);
806
	const loadMore = ae.getReadyMsgBytes() < ae.getTotalMsgBytes();
807
808
	if (msgCount > 0) {
809
		tabs[TAB_NOTES].max = 2 + Math.floor((msgCount - (loadMore? 0 : 1)) / rowsPerPage);
810
		document.getElementById("btn_rght").disabled = (tabs[TAB_NOTES].cur >= tabs[TAB_NOTES].max);
811
		tbl.replaceChildren();
812
813
		let skipMsgs = rowsPerPage * (tabs[TAB_NOTES].cur - 2);
814
		let numAdd = 0;
815
816
		for (let i = 0; numAdd < rowsPerPage && i < ae.getUplMsgCount(); i++) {
817
			if (skipMsgs > 0) {
818
				skipMsgs--;
819
				continue;
820
			}
821
822
			const row = tbl.insertRow(-1);
823
			row.setAttribute("data-msgid", ae.getUplMsgId(i));
824
			row.className = "rowfile";
825
826
			let cell = row.insertCell(-1);
827
			cell.textContent = new Date(ae.getUplMsgTime(i) * 1000).toISOString().slice(0, 10);
828
			cell.onclick = function() {displayFile(false, i, null);};
829
830
			cell = row.insertCell(-1);
831
			cell.textContent = (ae.getUplMsgBytes(i) / 1024).toFixed(0).padStart(4, " ");
832
			cell.onclick = function() {displayFile(false, i, null);};
833
834
			cell = row.insertCell(-1);
835
			const parentNum = ae.getUplMsgParent(i);
836
			if (typeof(parentNum) === "number") {
837
				cell.textContent = ae.getExtMsgTitle(parentNum);
838
				cell.onclick = function() {displayMsg(false, false, parentNum);};
839
			} else if (parentNum === false) {
840
				cell.textContent = "Upload";
841
			} else {
842
				cell.textContent = "Unknown";
843
			}
844
845
			cell = row.insertCell(-1);
846
			cell.textContent = ae.getUplMsgTitle(i);
847
			cell.onclick = function() {displayFile(false, i, null);};
848
849
			cell = row.insertCell(-1);
850
			const btn = document.createElement("button");
851
			btn.setAttribute("data-msgid", ae.getUplMsgId(i));
852
			btn.type = "button";
853
			btn.textContent = "X";
854
			btn.onclick = function() {
855
				ae.Message_Delete(this.getAttribute("data-msgid"), function(error) {
856
					if (error === 0) showFiles();
857
					else errorDialog(error);
858
				});
859
			};
860
			cell.appendChild(btn);
861
862
			numAdd++;
863
		}
864
865
		if (vaultPage >= 0) {
866
			for (let i = 0; numAdd < rowsPerPage && i < 256; i++) {
867
				if (vault.getFileSize(i) < 1) continue;
868
869
				if (skipMsgs > 0) {
870
					skipMsgs--;
871
					continue;
872
				}
873
874
				const row = tbl.insertRow(-1);
875
				row.className = "rowfile";
876
877
				let cell = row.insertCell(-1);
878
				cell.textContent = new Date(vault.getFileTime(i) * 1000).toISOString().slice(0, 10);
879
880
				cell = row.insertCell(-1);
881
				cell.textContent = (vault.getFileSize(i) / 1024).toFixed(0).padStart(4, " ");
882
883
				cell = row.insertCell(-1);
884
				cell.textContent = "Vault";
885
886
				cell = row.insertCell(-1);
887
				cell.textContent = vault.getFilePath(i);
888
				cell.onclick = function() {vault.downloadFile(i, function(m,p){}, function(msg) {
0 ignored issues
show
Unused Code introduced by
The parameter m is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter p is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
889
					if (msg !== "Done") errorDialog(404);
890
				});};
891
892
				cell = row.insertCell(-1);
893
				const btn = document.createElement("button");
894
				btn.type = "button";
895
				btn.textContent = "X";
896
				btn.onclick = function() {
897
					vault.deleteFile(i, function(error) {
898
						if (error === 0) showFiles();
899
						else errorDialog(error);
900
					});
901
				};
902
				cell.appendChild(btn);
903
904
				numAdd++;
905
			}
906
		}
907
	} else tabs[TAB_NOTES].max = 2;
908
909
	if (loadMore && tabs[TAB_NOTES].cur >= tabs[TAB_NOTES].max) {
910
		const row = tbl.insertRow(-1);
911
		row.className = "rowfilex";
912
913
		let cell = row.insertCell(-1);
914
		if (ae.getReadyMsgBytes() < ae.getTotalMsgBytes()) {
915
			cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
916
			cell.onclick = function() {
917
				tbl.style.opacity = 0.5;
918
919
				ae.Message_Browse(false, false, function(errorBrowse) {
920
					tbl.style.opacity = 1;
921
922
					if (errorBrowse !== 0) {
923
						errorDialog(errorBrowse);
924
						return;
925
					}
926
927
					showFiles();
928
				});
929
			};
930
		}
931
932
		cell = row.insertCell(-1);
0 ignored issues
show
Unused Code introduced by
The assignment to variable cell seems to be never used. Consider removing it.
Loading history...
933
	}
934
}
935
936
function addAccountToTable(i) {
937
	if (ae.getOwnUid() === ae.admin_getUserUid(i)) return;
938
939
	const row = document.getElementById("tbd_accs").insertRow(-1);
940
	let cell;
941
	cell = row.insertCell(-1); cell.textContent = ae.uidToName(ae.admin_getUserUid(i));
942
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.admin_getUserKib(i) / 1024);
943
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserNrm(i);
944
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserShd(i);
945
946
	cell = row.insertCell(-1);
947
	let btn = document.createElement("button");
948
	btn.type = "button";
949
	btn.textContent = "+";
950
	btn.disabled = (ae.admin_getUserLvl(i) === 3);
951
	btn.onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(ae.admin_getUserUid(i), ae.admin_getUserLvl(i) + 1, c);};
952
	cell.appendChild(btn);
953
954
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserLvl(i);
955
956
	cell = row.insertCell(-1);
957
	btn = document.createElement("button");
958
	btn.type = "button";
959
	btn.textContent = "−";
960
	btn.disabled = (ae.admin_getUserLvl(i) === 0);
961
	btn.onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(ae.admin_getUserUid(i), ae.admin_getUserLvl(i) - 1, c);};
962
	cell.appendChild(btn);
963
964
	cell = row.insertCell(-1);
965
	btn = document.createElement("button");
966
	btn.type = "button";
967
	btn.textContent = "X";
968
	btn.onclick = function() {
969
		const tr = this.parentElement.parentElement;
970
		ae.Account_Delete(ae.admin_getUserUid(i), function(error) {
971
			if (error === 0) tr.remove(); else errorDialog(error);
972
		});
973
	};
974
	cell.appendChild(btn);
975
}
976
977
function updateLimits() {
978
	const tbl = document.querySelector("#tbl_limits > tbody");
979
980
	if (ae.isUserAdmin()) {
981
		for (let i = 0; i < 4; i++) {
982
			tbl.rows[i].cells[1].children[0].value = ae.getLimitStorage(i);
983
			tbl.rows[i].cells[2].children[0].value = ae.getLimitNormalA(i);
984
			tbl.rows[i].cells[3].children[0].value = ae.getLimitShieldA(i);
985
		}
986
	} else {
987
		const lvl = ae.getOwnLevel();
988
		tbl.rows[lvl].cells[1].children[0].value = ae.getLimitStorage(lvl);
989
		tbl.rows[lvl].cells[2].children[0].value = ae.getLimitNormalA(lvl);
990
		tbl.rows[lvl].cells[3].children[0].value = ae.getLimitShieldA(lvl);
991
	}
992
}
993
994
function deleteAddress(addr) {
995
	const buttons = document.querySelectorAll("#tbl_addrs button");
996
	buttons.forEach(function(btn) {btn.disabled = true;});
997
998
	let addressToDelete = -1;
999
	for (let i = 0; i < ae.getAddressCount(); i++) {
1000
		if (addr === ae.getAddress(i)) {
1001
			addressToDelete = i;
1002
			break;
1003
		}
1004
	}
1005
1006
	if (addressToDelete === -1) return;
1007
1008
	ae.Address_Delete(addressToDelete, function(error1) {
1009
		if (error1 !== 0) {
1010
			buttons.forEach(function(btn) {btn.disabled = false;});
1011
			errorDialog(error1);
1012
			return;
1013
		}
1014
1015
		document.getElementById("tbl_addrs").deleteRow(addressToDelete);
1016
		document.getElementById("write_from").remove(addressToDelete);
1017
1018
		if (ae.getAddressCountNormal() > 0) {
1019
			const apkList = document.getElementById("getapk_addr");
1020
			for (let i = 0; i < apkList.children.length; i++) {
1021
				if (apkList.children[i].value === addr) {
1022
					apkList.remove(i);
1023
					break;
1024
				}
1025
			}
1026
		} else {
1027
			document.getElementById("getapk_addr").replaceChildren();
1028
		}
1029
1030
		updateAddressCounts();
1031
1032
		ae.Private_Update(function(error2) {
1033
			buttons.forEach(function(btn) {btn.disabled = false;});
1034
			if (error2) errorDialog(error2);
1035
		});
1036
	});
1037
}
1038
1039
function setTab(isHistory, tabNum, pageNum) {
1040
	tab = tabNum;
1041
	if (pageNum !== -1) tabs[tab].cur = pageNum;
1042
1043
	document.querySelectorAll("#main1 > nav:first-of-type > button").forEach(function(btn, i) {
1044
		document.querySelectorAll("#main1 > .mid > div")[i].hidden = (tab !== i);
1045
		btn.disabled = (tab === i);
1046
	});
1047
1048
	const bigScreen = window.matchMedia("(min-width: 80em)").matches;
1049
	document.getElementById("main2").hidden = !bigScreen;
1050
	document.getElementById("btn_leave").disabled = bigScreen;
1051
1052
	switch (tab) {
1053
		case TAB_INBOX: showInbox(); break;
1054
		case TAB_DRBOX: showDrbox(); break;
1055
1056
		case TAB_WRITE:
1057
			if (tabs[tab].cur === 0) {
1058
				document.getElementById("div_write_1").hidden = false;
1059
				document.getElementById("div_write_2").hidden = true;
1060
				document.getElementById("write_recv").focus();
1061
			} else if (!writeVerify()) {
1062
				tabs[TAB_WRITE].cur = 0;
1063
				return;
1064
			}
1065
		break;
1066
1067
		case TAB_NOTES:
1068
			if (vaultPage === -2) {
1069
				vaultPage = -1;
1070
1071
				vault.downloadIndex(function(err) {
1072
					if (err === 0) {
1073
						vaultPage = 0;
1074
					}
1075
				});
1076
			}
1077
1078
			switch (tabs[tab].cur) {
1079
				case 0:
1080
					document.getElementById("div_notes").children[0].hidden = false;
1081
					document.getElementById("div_notes").children[1].hidden = true;
1082
					document.getElementById("div_notes").children[2].hidden = true;
1083
				break;
1084
1085
				case 1:
1086
					document.getElementById("div_notes").children[0].hidden = true;
1087
					document.getElementById("div_notes").children[1].hidden = false;
1088
					document.getElementById("div_notes").children[2].hidden = true;
1089
1090
					document.querySelector("#div_notepad meter").value = ae.getPrivateExtraSpace() / ae.getPrivateExtraSpaceMax();
1091
				break;
1092
1093
				case 2:
1094
					document.getElementById("div_notes").children[0].hidden = true;
1095
					document.getElementById("div_notes").children[1].hidden = true;
1096
					document.getElementById("div_notes").children[2].hidden = false;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
1097
1098
				default:
1099
					showFiles();
1100
			}
1101
		break;
1102
1103
		case TAB_TOOLS:
1104
			for (let i = 0; i <= tabs[tab].max; i++) {
1105
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1106
			}
1107
		break;
1108
	}
1109
1110
	document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1111
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1112
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1113
	document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1114
1115
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
1116
}
1117
1118
window.onresize = function() {
1119
	setTab(true, tab, tabs[tab].cur);
1120
}
1121
1122
function clearWrite() {
1123
	setTab(false, TAB_WRITE, 0);
1124
1125
	document.querySelector("#write2_pkey > input").value = "";
1126
	document.getElementById("write_body").value = "";
1127
	document.getElementById("write_subj").value = "";
1128
	document.getElementById("write_subj").readOnly = false;
1129
	document.getElementById("write_subj").setAttribute("data-replyid", "");
1130
	document.getElementById("write_recv").value = "";
1131
	document.getElementById("write_recv").readOnly = false;
1132
	document.getElementById("write_recv").focus();
1133
}
1134
1135
function refreshContactList() {
1136
	let opts = [];
1137
1138
	for (let i = 0; i < ae.getContactCount(); i++) {
1139
		const el = document.createElement("option");
1140
		el.value = ae.getContactMail(i);
1141
		opts.push(el);
1142
	}
1143
1144
	if (ae.isUserAdmin()) {
1145
		const el = document.createElement("option");
1146
		el.value = "public";
1147
		opts.push(el);
1148
	}
1149
1150
	document.getElementById("contact_emails").replaceChildren(...opts);
1151
}
1152
1153
function addContact(mail, name, note) {
1154
	const tbl = document.getElementById("tbl_ctact");
1155
	const row = tbl.insertRow(-1);
1156
1157
	let cell = row.insertCell(-1);
1158
	cell.autocapitalize = "off";
1159
	cell.contentEditable = true;
1160
	cell.inputMode = "email";
1161
	cell.spellcheck = false;
1162
	cell.textContent = mail;
1163
1164
	cell = row.insertCell(-1);
1165
	cell.autocapitalize = "words";
1166
	cell.contentEditable = true;
1167
	cell.spellcheck = false;
1168
	cell.textContent = name;
1169
1170
	cell = row.insertCell(-1);
1171
	cell.autocapitalize = "off";
1172
	cell.contentEditable = true;
1173
	cell.spellcheck = false;
1174
	cell.textContent = note;
1175
1176
	cell = row.insertCell(-1);
1177
	const el = document.createElement("button");
1178
	el.type = "button";
1179
	el.textContent = "X";
1180
	el.onclick = function() {row.remove();};
1181
	cell.appendChild(el);
1182
}
1183
1184
function addContacts() {
1185
	for (let i = 0; i < ae.getContactCount(); i++) {
1186
		addContact(
1187
			ae.getContactMail(i),
1188
			ae.getContactName(i),
1189
			ae.getContactNote(i)
1190
		);
1191
	}
1192
1193
	refreshContactList();
1194
}
1195
1196
function addAddress(num) {
1197
	const addrTable = document.getElementById("tbl_addrs");
1198
	const row = addrTable.insertRow(-1);
1199
	const addr = ae.getAddress(num);
1200
1201
	let cell = row.insertCell(-1);
1202
	cell.textContent = addr;
1203
	cell.onclick = function() {navigator.clipboard.writeText(((this.textContent.length === 16) ? ae.shieldMix(this.textContent, 0) : this.textContent) + "@" + ae.getDomainEml());};
1204
1205
	cell = row.insertCell(-1);
1206
	let el = document.createElement("input");
1207
	el.type = "checkbox";
1208
	el.checked = ae.getAddressAccInt(num);
1209
	cell.appendChild(el);
1210
1211
	cell = row.insertCell(-1);
1212
	el = document.createElement("input");
1213
	el.type = "checkbox";
1214
	el.checked = ae.getAddressAccExt(num);
1215
	cell.appendChild(el);
1216
1217
	cell = row.insertCell(-1);
1218
	el = document.createElement("input");
1219
	el.type = "checkbox";
1220
	el.checked = ae.getAddressAllVer(num);
1221
	cell.appendChild(el);
1222
1223
	cell = row.insertCell(-1);
1224
	el = document.createElement("input");
1225
	el.type = "checkbox";
1226
	el.checked = ae.getAddressAttach(num);
1227
	cell.appendChild(el);
1228
1229
	cell = row.insertCell(-1);
1230
	el = document.createElement("input");
1231
	el.type = "checkbox";
1232
	el.checked = ae.getAddressSecure(num);
1233
	cell.appendChild(el);
1234
1235
	cell = row.insertCell(-1);
1236
	el = document.createElement("input");
1237
	el.type = "checkbox";
1238
	el.checked = ae.getAddressOrigin(num);
1239
	cell.appendChild(el);
1240
1241
	cell = row.insertCell(-1);
1242
	el = document.createElement("button");
1243
	el.type = "button";
1244
	el.textContent = "X";
1245
	el.onclick = function() {deleteAddress(addr);};
1246
	cell.appendChild(el);
1247
1248
	el = document.createElement("option");
1249
	el.value = addr;
1250
	el.textContent = addr + "@" + ae.getDomainEml();
1251
	document.getElementById("write_from").appendChild(el);
1252
1253
	if (addr.length !== 16) {
1254
		el = document.createElement("option");
1255
		el.value = addr;
1256
		el.textContent = addr;
1257
		document.getElementById("getapk_addr").appendChild(el);
1258
	}
1259
}
1260
1261
function addAddresses() {
1262
	for (let i = 0; i < ae.getAddressCount(); i++) {
1263
		addAddress(i);
1264
	}
1265
}
1266
1267
function addressCreate(addr) {
1268
	document.getElementById("btn_address_create_normal").disabled = true;
1269
	document.getElementById("btn_address_create_shield").disabled = true;
1270
1271
	ae.Address_Create(addr, function(error1) {
1272
		if (error1 !== 0) {
1273
			updateAddressButtons();
1274
			errorDialog(error1, (addr !== "SHIELD") ? document.getElementById("txt_address_create_normal") : null);
1275
			return;
1276
		}
1277
1278
		ae.Private_Update(function(error2) {
1279
			updateAddressCounts();
1280
1281
			addAddress(ae.getAddressCount() - 1);
1282
			if (addr !== "SHIELD") {
1283
				document.getElementById("txt_address_create_normal").value = "";
1284
				document.getElementById("txt_address_create_normal").focus();
1285
			}
1286
1287
			if (error2 !== 0) errorDialog(error2, (addr !== "SHIELD") ? document.getElementById("txt_address_create_normal") : null);
1288
		});
1289
	});
1290
}
1291
1292
function reloadAccount() {
1293
	updateLimits();
1294
	addOwnAccount();
1295
	addContacts();
1296
	addAddresses();
1297
	updateAddressCounts();
1298
1299
	document.getElementById("fs_admin").disabled = !ae.isUserAdmin();
1300
	document.getElementById("txt_notepad").value = ae.getPrivateExtra();
1301
}
1302
1303
function writeVerify() {
1304
	if (
1305
	   !document.getElementById("write_recv").reportValidity()
1306
	|| !document.getElementById("write_subj").reportValidity()
1307
	|| !document.getElementById("write_body").reportValidity()
1308
	) return false;
1309
1310
	document.getElementById("div_write_1").hidden = true;
1311
	document.getElementById("div_write_2").hidden = false;
1312
1313
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1314
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1315
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1316
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1317
1318
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1319
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.getDomainEml();
1320
		document.getElementById("write2_pkey").hidden = true;
1321
	} else {
1322
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1323
		document.getElementById("write2_pkey").hidden = (document.getElementById("write_recv").value === "public");
1324
	}
1325
1326
	document.querySelector("#write2_send > button").disabled = false;
1327
	document.getElementById("write2_btntxt").textContent = (document.getElementById("write_recv").value === "public") ? "Make" : "Send to";
1328
	return true;
1329
}
1330
1331
// Interface elements
1332
if (window.matchMedia("(prefers-color-scheme: light)").matches) document.querySelector("head > meta[name='theme-color']").content = "#eef";
1333
window.matchMedia("(prefers-color-scheme: light)").onchange = function() {document.querySelector("head > meta[name='theme-color']").content = window.matchMedia("(prefers-color-scheme: light)").matches? "#eef" : "#001";};
1334
1335
window.onpopstate = function(event) {
1336
	if (!isReady || !event.state) return;
1337
	setTab(true, event.state.tab, event.state.page);
1338
	msgDisplay = event.state.msg;
1339
1340
	if (msgDisplay) {
1341
		switch (msgDisplay.type) {
1342
			case "ext": displayMsg(true, false, msgDisplay.num); break;
1343
			case "int": displayMsg(true, true, msgDisplay.num); break;
1344
			case "out": displayOutMsg(true, msgDisplay.num); break;
1345
			case "upl": displayFile(true, msgDisplay.num, null); break;
1346
			case "ext_exp": displayExport(true, false, msgDisplay.num); break;
1347
			case "int_exp": displayExport(true, true, msgDisplay.num); break;
1348
		}
1349
	}
1350
};
1351
1352
document.querySelectorAll("#main1 > nav:first-of-type > button").forEach(function(btn, i) {
1353
	btn.onclick = function() {setTab(false, i, -1);};
1354
});
1355
1356
document.getElementById("btn_left").onclick = function() {
1357
	setTab(false, tab, tabs[tab].cur - 1);
1358
};
1359
1360
document.getElementById("btn_rght").onclick = function() {
1361
	setTab(false, tab, tabs[tab].cur + 1);
1362
};
1363
1364
1365
document.getElementById("btn_dele").onclick = function() {
1366
	this.blur();
1367
1368
	if (tab === TAB_WRITE) clearWrite();
1369
};
1370
1371
document.getElementById("btn_updt").onclick = function() {
1372
	const btn = this;
1373
	btn.disabled = true;
1374
	btn.blur();
1375
1376
	if (tab === TAB_INBOX) {
1377
		document.getElementById("tbl_inbox").style.opacity = 0.5;
1378
1379
		ae.Message_Browse(true, false, function(error) {
1380
			btn.disabled = false;
1381
			document.getElementById("tbl_inbox").style.opacity = 1;
1382
1383
			if (error === 0) {
1384
				showInbox();
1385
			} else {
1386
				errorDialog(error);
1387
			}
1388
		});
1389
	}
1390
};
1391
1392
document.getElementById("btn_mdele").onclick = function() {
1393
	const delId = document.querySelector("article").getAttribute("data-msgid");
1394
	if (!delId) return;
1395
1396
	const btn = this;
1397
	btn.blur();
1398
	btn.disabled = true;
1399
1400
	ae.Message_Delete(delId, function(error) {
1401
		if (error !== 0) {
1402
			btn.disabled = false;
1403
			errorDialog(error);
1404
			return;
1405
		}
1406
1407
		switch (tab) {
1408
			case TAB_INBOX: showInbox(); break;
1409
			case TAB_DRBOX: showDrbox(); break;
1410
			case TAB_NOTES: showFiles(); break;
1411
		}
1412
	});
1413
};
1414
1415
document.getElementById("btn_leave").onclick = function() {
1416
	document.getElementById("main2").hidden = true;
1417
	document.getElementById("main1").hidden = false;
1418
};
1419
1420
document.getElementById("btn_newcontact").onclick = function() {
1421
	addContact("", "", "");
1422
};
1423
1424
document.getElementById("btn_savecontacts").onclick = function() {
1425
	while (ae.getContactCount() > 0) {
1426
		ae.deleteContact(0);
1427
	}
1428
1429
	for (const row of document.getElementById("tbl_ctact").rows) {
1430
		ae.addContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1431
	}
1432
1433
	refreshContactList();
1434
1435
	const btn = this;
1436
	btn.disabled = true;
1437
1438
	ae.Private_Update(function(error) {
1439
		btn.disabled = false;
1440
		if (error) errorDialog(error);
1441
	});
1442
};
1443
1444
document.getElementById("btn_address_create_normal").onclick = function() {
1445
	if (ae.getAddressCountNormal() >= ae.getLimitNormalA(ae.getOwnLevel()) || ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31) return;
1446
1447
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1448
	if (!txtNewAddr.reportValidity()) return;
1449
1450
	addressCreate(txtNewAddr.value.toLowerCase());
1451
};
1452
1453
document.getElementById("txt_address_create_normal").onkeyup = function(event) {
1454
	if (event.key !== "Enter") return;
1455
	event.preventDefault();
1456
	document.getElementById("btn_address_create_normal").click();
1457
};
1458
1459
document.getElementById("btn_address_create_shield").onclick = function() {
1460
	if (ae.getAddressCountShield() >= ae.getLimitShieldA(ae.getOwnLevel()) || ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31) return;
1461
1462
	addressCreate("SHIELD");
1463
};
1464
1465
document.getElementById("btn_address_update").onclick = function() {
1466
	const btn = this;
1467
	btn.disabled = true;
1468
1469
	const rows = document.getElementById("tbl_addrs").rows;
1470
1471
	for (let i = 0; i < rows.length; i++) {
1472
		ae.setAddressAccInt(i, rows[i].getElementsByTagName("input")[0].checked);
1473
		ae.setAddressAccExt(i, rows[i].getElementsByTagName("input")[1].checked);
1474
		ae.setAddressAllVer(i, rows[i].getElementsByTagName("input")[2].checked);
1475
		ae.setAddressAttach(i, rows[i].getElementsByTagName("input")[3].checked);
1476
		ae.setAddressSecure(i, rows[i].getElementsByTagName("input")[4].checked);
1477
		ae.setAddressOrigin(i, rows[i].getElementsByTagName("input")[5].checked);
1478
	}
1479
1480
	ae.Address_Update(function(error) {
1481
		btn.disabled = false;
1482
		if (error) errorDialog(error);
1483
	});
1484
};
1485
1486
1487
document.getElementById("txt_sender").onkeyup = function(event) {
1488
	if (event.key !== "Enter") return;
1489
	event.preventDefault();
1490
	document.getElementById("btn_sender").click();
1491
};
1492
1493
document.getElementById("btn_reg").onclick = function() {
1494
	const btn = document.getElementById("btn_reg");
1495
	const uak = document.getElementById("txt_reg_uak");
1496
	const epk = document.getElementById("txt_reg_epk");
1497
1498
	if (!uak.reportValidity() || !epk.reportValidity()) return;
1499
	btn.disabled = true;
1500
	uak.disabled = true;
1501
	epk.disabled = true;
1502
1503
	ae.Account_Create(uak.value, epk.value, function(error) {
1504
		if (error === 0) {
1505
			addAccountToTable(ae.admin_getUserCount() - 1);
1506
			uak.value = "";
1507
			epk.value = "";
1508
		} else errorDialog(error);
1509
1510
		btn.disabled = false;
1511
		uak.disabled = false;
1512
		epk.disabled = false;
1513
	});
1514
};
1515
1516
document.getElementById("chk_dng_usr").onclick = function() {
1517
	document.getElementById("btn_lowme").disabled = !this.checked || (ae.getOwnLevel() === 0);
1518
	document.getElementById("btn_erame").disabled = !this.checked;
1519
	document.getElementById("btn_delme").disabled = !this.checked;
1520
};
1521
1522
document.getElementById("btn_erame").onclick = function() {
1523
	ae.Message_Delete("ALL", function(error) {
1524
		if (error === 0) {
1525
			document.getElementById("chk_dng_usr").checked = false;
1526
			document.getElementById("chk_dng_usr").onclick();
1527
		} else errorDialog(error);
1528
	});
1529
};
1530
1531
document.getElementById("btn_notepad_restore").onclick = function() {
1532
	document.getElementById("txt_notepad").value = ae.getPrivateExtra();
1533
	document.getElementById("btn_notepad_savepad").disabled = true;
1534
	document.getElementById("txt_notepad").oninput = function() {
1535
		this.oninput = null;
1536
		document.getElementById("btn_notepad_savepad").disabled = false;
1537
		document.getElementById("btn_notepad_savepad").textContent = "Save";
1538
	};
1539
};
1540
1541
document.getElementById("txt_notepad").oninput = function() {
1542
	document.getElementById("btn_notepad_savepad").disabled = false;
1543
};
1544
1545
document.getElementById("btn_notepad_savepad").onclick = function() {
1546
	const btn = this;
1547
	btn.disabled = true;
1548
1549
	const error = ae.setPrivateExtra(document.getElementById("txt_notepad").value);
1550
	if (error !== 0) {
1551
		btn.disabled = false;
1552
		errorDialog(error);
1553
		return;
1554
	}
1555
1556
	ae.Private_Update(function(error2) {
1557
		if (error2 !== 0) {
1558
			btn.disabled = false;
1559
			errorDialog(error2);
1560
		} else {
1561
			document.querySelector("#div_notepad meter").value = ae.getPrivateExtraSpace() / ae.getPrivateExtraSpaceMax();
1562
			btn.textContent = "Saved";
1563
			document.getElementById("txt_notepad").oninput = function() {
1564
				this.oninput = null;
1565
				btn.textContent = "Save";
1566
				btn.disabled = false;
1567
			};
1568
		}
1569
	});
1570
};
1571
1572
document.getElementById("btn_notepad_saveupl").onclick = function() {
1573
	const np = document.getElementById("txt_notepad");
1574
	np.disabled = true;
1575
1576
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1577
	if (!fname.endsWith(".txt")) fname += ".txt";
1578
1579
	ae.Message_Upload(fname, np.value, function(error) {
1580
		if (error === 0) {
1581
			np.value = "";
1582
			showFiles();
1583
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.getTotalMsgBytes() / 1024 / 1024);
1584
		} else errorDialog(error);
1585
1586
		np.disabled = false;
1587
	});
1588
};
1589
1590
document.getElementById("btn_upload").onclick = function() {
1591
	const btn = this;
1592
	const fileSelector = document.createElement("input");
1593
	fileSelector.type = "file";
1594
	fileSelector.click();
1595
1596
	fileSelector.onchange = function() {
1597
		btn.disabled = true;
1598
1599
		const reader = new FileReader();
1600
		reader.onload = function() {
1601
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(error) {
1602
				if (error === 0) {
1603
					showFiles();
1604
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.getTotalMsgBytes() / 1024 / 1024);
1605
				} else errorDialog(error);
1606
1607
				btn.disabled = false;
1608
			});
1609
		};
1610
1611
		reader.readAsArrayBuffer(fileSelector.files[0]);
1612
	};
1613
};
1614
1615
document.getElementById("btn_pg").onclick = function() {
1616
//	localStorage.greeting = document.getElementById("txt_pg").value;
1617
};
1618
1619
document.querySelector("#write2_send > button").onclick = function() {
1620
	const btn = this;
1621
	btn.disabled = true;
1622
1623
	// Public announcement
1624
	if (document.getElementById("write2_recv").textContent === "public") {
1625
		ae.Message_Public(document.getElementById("write_subj").value, document.getElementById("write_body").value, function(error) {
1626
			if (error !== 0) {
1627
				document.getElementById("write2_btntxt").textContent = "Retry making";
1628
				btn.disabled = false;
1629
				errorDialog(error);
1630
				return;
1631
			}
1632
1633
			clearWrite();
1634
			displayMsg(false, true, 0);
1635
		});
1636
1637
		return;
1638
	}
1639
1640
	// Email or internal message
1641
	let apk = null;
1642
	if (document.getElementById("write2_recv").textContent.indexOf("@") === -1) {
1643
		const elApk = document.querySelector("#write2_pkey > input");
1644
		if (!elApk.reportValidity()) {
1645
			btn.disabled = false;
1646
			return;
1647
		}
1648
1649
		try {apk = sodium.from_base64(elApk.value, sodium.base64_variants.ORIGINAL_NO_PADDING);}
1650
		catch(e) {
1651
			errorDialog(1); // Invalid input
1652
			btn.disabled = false;
1653
			return;
1654
		}
1655
	}
1656
1657
	document.getElementById("write2_btntxt").textContent = "Sending to";
1658
1659
	ae.Message_Create(
1660
		document.getElementById("write_subj").value,
1661
		document.getElementById("write_body").value,
1662
		document.getElementById("write_from").value,
1663
		document.getElementById("write_recv").value,
1664
		document.getElementById("write_subj").getAttribute("data-replyid"),
1665
		apk,
1666
		function(error) {
1667
			if (error !== 0) {
1668
				errorDialog(error);
1669
				document.getElementById("write2_btntxt").textContent = "Retry sending to";
1670
				btn.disabled = false;
1671
				return;
1672
			}
1673
1674
			showDrbox();
1675
			clearWrite();
1676
			displayOutMsg(false, 0);
1677
		}
1678
	);
1679
};
1680
1681
document.getElementById("btn_sender").onclick = function() {
1682
	ae.Message_Sender(document.getElementById("txt_sender_hash").value, Date.parse(document.getElementById("txt_sender_date").value) / 1000, function(error, result) {
1683
		if (error !== 0) {
1684
			errorDialog(error);
1685
			return;
1686
		}
1687
1688
		document.getElementById("txt_sender_res").value = result;
1689
	});
1690
};
1691
1692
document.getElementById("btn_limits").onclick = function() {
1693
	const btn = this;
1694
	btn.disabled = true;
1695
1696
	const mib = [parseInt(document.getElementById("lim_mib0").value, 10), parseInt(document.getElementById("lim_mib1").value, 10), parseInt(document.getElementById("lim_mib2").value, 10), parseInt(document.getElementById("lim_mib3").value, 10)];
1697
	const nrm = [parseInt(document.getElementById("lim_nrm0").value, 10), parseInt(document.getElementById("lim_nrm1").value, 10), parseInt(document.getElementById("lim_nrm2").value, 10), parseInt(document.getElementById("lim_nrm3").value, 10)];
1698
	const shd = [parseInt(document.getElementById("lim_shd0").value, 10), parseInt(document.getElementById("lim_shd1").value, 10), parseInt(document.getElementById("lim_shd2").value, 10), parseInt(document.getElementById("lim_shd3").value, 10)];
1699
1700
	ae.Setting_Limits(mib, nrm, shd, function(error) {
1701
		btn.disabled = false;
1702
1703
		if (error !== 0) {
1704
			errorDialog(error);
1705
		} else {
1706
			updateAddressCounts();
1707
		}
1708
	});
1709
};
1710
1711
document.getElementById("getapk_addr").onchange = function() {
1712
	document.getElementById("getapk_result").textContent = ae.getOwnApk(document.getElementById("getapk_addr").value);
1713
};
1714
1715
document.getElementById("txt_umk").onfocus = function() {
1716
//	document.getElementById("greeting").textContent = localStorage.greeting;
1717
};
1718
1719
document.getElementById("txt_umk").onkeyup = function(event) {
1720
	if (event.key !== "Enter") return;
1721
	event.preventDefault();
1722
	document.getElementById("btn_enter").click();
1723
};
1724
1725
document.getElementById("btn_enter").onclick = function() {
1726
	const txtUmk = document.getElementById("txt_umk");
1727
1728
	if (txtUmk.value === "") {
1729
		ae.reset();
1730
		document.getElementById("greeting").textContent = "Data cleared";
1731
		return;
1732
	}
1733
1734
	if (!txtUmk.reportValidity()) return;
1735
1736
	const btn = this;
1737
	btn.disabled = true;
1738
1739
	document.getElementById("txt_umk").disabled = true;
1740
1741
	ae.setKeys(txtUmk.value, function(successSetKeys) {
1742
		if (!successSetKeys) {
1743
			document.getElementById("txt_umk").disabled = false;
1744
			txtUmk.focus();
1745
1746
			document.getElementById("greeting").textContent = "SetKeys failed";
1747
			btn.disabled = false;
1748
			return;
1749
		}
1750
1751
		document.body.style.cursor = "wait";
1752
		document.getElementById("greeting").textContent = "Connecting...";
1753
1754
		if (vaultPage === -3) {
1755
			vault.setKeys(txtUmk.value, function(vaultKeysOk) {
1756
				if (vaultKeysOk) vaultPage = -2;
1757
			});
1758
		}
1759
1760
		ae.Message_Browse(true, true, function(errorBrowse) {
1761
			document.body.style.cursor = "";
1762
1763
			if (errorBrowse !== 0 && errorBrowse !== 0x09) {
1764
				let errorMsg = ae.getErrorMessage(errorBrowse);
1765
				if (typeof(errorMsg) == "object") errorMsg = errorMsg[1];
1766
1767
				document.getElementById("greeting").textContent = errorMsg + " ("+ ((errorBrowse >= 400) ? errorBrowse : "0x" + errorBrowse.toString(16).padStart(2, "0").toUpperCase()) + ")";
1768
				document.getElementById("txt_umk").disabled = false;
1769
				btn.disabled = false;
1770
				btn.focus();
1771
				return;
1772
			}
1773
1774
			txtUmk.value = "";
1775
			document.getElementById("div_begin").hidden = true;
1776
			document.getElementById("div_main").hidden = false;
1777
			isReady = true;
1778
			reloadAccount();
1779
			history.replaceState({tab: 0, page: 0, msg: msgDisplay}, null);
1780
			setTab(true, 0, 0);
1781
1782
			if (errorBrowse !== 0) errorDialog(errorBrowse);
1783
			if (!ae.isUserAdmin()) return;
1784
1785
			ae.Account_Browse(function(errorAcc) {
1786
				if (errorAcc === 0) {
1787
					for (let i = 0; i < ae.admin_getUserCount(); i++) {addAccountToTable(i);}
1788
					updateLimits();
1789
				} else {
1790
					errorDialog(errorAcc);
1791
				}
1792
			});
1793
		});
1794
	});
1795
};
1796
1797
});
1798